﻿using System;

namespace LeRenard
{
    /// <summary>
    /// Helper class for the Object.ToString() implemenation.
    /// </summary>
    public static class ToStringHelper
    {
        /// <summary>
        /// Format used when an object is null.
        /// </summary>
        public const string NULL_STRING = "(*null)";

        /// <summary>
        /// Format used when an <see cref="Exception"/> occured.
        /// </summary>
        public const string EXCEPTION_STRING = "(*ex!{0})";

        /// <summary>
        /// Performs the .ToString() method call on the given <paramref name="object"/>.
        /// </summary>
        /// <typeparam name="TObject">The type of the <paramref name="object"/>.</typeparam>
        /// <param name="object">The object to perform a .ToString() method call on.</param>
        /// <returns>The result of the .ToString() method call, or <see cref="NULL_STRING"/> when <paramref name="object"/> is null.</returns>
        public static string For<TObject>(TObject @object)
        {
            return For<TObject>(@object, o => o.ToString());
        }

        /// <summary>
        /// Returns the value defined in the <paramref name="displayValueSelector"/>, unless the <paramref name="object"/> is null.
        /// </summary>
        /// <typeparam name="TObject">The type of the <paramref name="object"/>.</typeparam>
        /// <param name="object">The object to generate a display value for, this object is fed to the <paramref name="displayValueSelector"/>.</param>
        /// <param name="displayValueSelector"><see cref="Expression"/> that defines how the value will be presented.</param>
        /// <returns>The result of the <paramref name="displayValueSelector"/> or <see cref="NULL_STRING"/> when <paramref name="object"/> is null, or <see cref="EXCEPTION_STRING"/> when <paramref name="displayValueSelector"/> caused an exception.</returns>
        public static string For<TObject>(TObject @object, Func<TObject, string> displayValueSelector)
        {
            try
            {
                if (@object == null)
                    return NULL_STRING;

                var displayValue = displayValueSelector.Invoke(@object);
                return displayValue;
            }
            catch (Exception ex)
            {
                return EXCEPTION_STRING.FormatWith(
                        ex.GetType().ToFriendlyName()
                    );
            }
        }
    }
}
